Skip to content

feat: Git extension stage 1 — bundled extensions/git with hooks on all core commands#1941

Draft
Copilot wants to merge 6 commits intomainfrom
copilot/extract-git-branching-operations
Draft

feat: Git extension stage 1 — bundled extensions/git with hooks on all core commands#1941
Copilot wants to merge 6 commits intomainfrom
copilot/extract-git-branching-operations

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 23, 2026

Stage 1: Git Extension (opt-in, bundled)

Extracts Git branching operations into a self-contained extensions/git/ extension. This is stage 1 — the extension is opt-in via specify extension add git (resolves locally from the bundled copy, no network required). Core git init and branching code remains unchanged.

Refs: #841, #1382, #1066, #1791, #1191


Extension structure (extensions/git/)

5 commands:

Command Description
speckit.git.initialize Initialize a Git repo with configurable commit message
speckit.git.feature Create feature branch (sequential/timestamp numbering)
speckit.git.validate Validate branch follows naming conventions
speckit.git.remote Detect Git remote URL for GitHub integration
speckit.git.commit Auto-commit changes (configurable per-command)

18 hooks across all 9 core commands:

Hook Command Purpose
before_constitution speckit.git.initialize Init git repo before constitution
before_specify speckit.git.feature Create feature branch before spec
before_clarify/plan/tasks/implement/checklist/analyze/taskstoissues speckit.git.commit Commit outstanding changes before command
after_constitution/specify/clarify/plan/tasks/implement/checklist/analyze/taskstoissues speckit.git.commit Auto-commit after command completes

Scripts (bash + powershell):

  • create-new-feature.{sh,ps1} — branch creation with sequential/timestamp numbering
  • initialize-repo.{sh,ps1} — git init with configurable commit message
  • auto-commit.{sh,ps1} — per-command auto-commit with config-driven enable/disable and custom messages
  • git-common.{sh,ps1} — extracted has_git() and check_feature_branch() helpers

All scripts capture git output and suppress it on success; full output is included in error messages on failure.

Configuration (git-config.yml):

  • branch_numbering: sequential or timestamp
  • init_commit_message: custom initial commit message
  • auto_commit: per-command enable/disable with custom commit messages (all disabled by default)

Hook system improvements

  • All 9 core commands now have hooks: Added before_*/after_* hook support to analyze, checklist, clarify, constitution, and taskstoissues (previously only specify, plan, tasks, implement had hooks)
  • Hooks-only extensions: Extensions can now provide only hooks (no commands required). The validation changed from "must provide at least one command" to "must provide at least one command or hook"
  • Removed before_commit/after_commit: These were documented as "planned" but never implemented and had no backing core command. Removed from API reference, user guide, and dev guide

Bundled extension install

  • pyproject.toml force-includes extensions/git into the wheel
  • _locate_bundled_extension() resolves bundled extensions from core_pack/ (wheel) or extensions/ (source checkout)
  • specify extension add git resolves locally before falling back to catalog — no network needed
  • Added git extension to catalog.json for discoverability via specify extension search

What stays in core (unchanged)

is_git_repo(), init_git_repo(), --branch-numbering flag, --no-git flag, get_current_branch(), SPECIFY_FEATURE env var, find_feature_dir_by_prefix(), specify.md template — all unchanged. The core {SCRIPT} flow continues to work as before.

Disable/re-enable

specify extension disable git   # stops all branch operations
specify extension enable git    # re-enables branching

Tests

37 new tests in tests/extensions/git/test_git_extension.py:

  • Manifest validation (commands, hooks, file existence)
  • Extension install via ExtensionManager
  • Bundled extension locator
  • initialize-repo.sh/.ps1 — init, skip-if-exists, custom commit message
  • create-new-feature.sh/.ps1 — sequential, timestamp, spec dir creation, increments, no-git degradation, dry-run
  • auto-commit.sh/.ps1 — disabled by default, per-command enable, custom messages, default fallback, no-changes skip, no-config skip, no-git skip
  • git-common.sh — has_git, check_feature_branch (sequential, timestamp, reject main, reject malformed)

Stage 2 (future)

  1. Auto-install during specify init (controlled by --no-git → don't install git extension)
  2. Remove core git init / is_git_repo / init_git_repobefore_constitution hook handles it
  3. Remove branch creation from specify.mdbefore_specify hook handles it via speckit.git.feature; change specify.md script ref from create-new-feature to check-prerequisites only
  4. Custom naming via presets (addresses [Feature request] Custom namespacing and branch naming conventions #1382 — override create-new-feature scripts)

Copilot AI changed the title [WIP] Extract Git/branching operations into extensions/git extension Extract Git/Branching operations into extensions/git extension (opt-out, auto-enabled) Mar 23, 2026
Copilot AI requested a review from mnriem March 23, 2026 21:34
@mnriem mnriem requested a review from Copilot March 23, 2026 21:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates git/branching workflow logic into a bundled extensions/git/ extension and wires it into specify init as an auto-enabled (opt-out) migration step, aiming to decouple branching behavior from core and reduce platform-specific breakages.

Changes:

  • Add a new extensions/git/ extension (manifest, commands, config template, and cross-platform scripts) for feature-branch creation/validation/remote detection.
  • Auto-install the bundled git extension during specify init and bundle it into the wheel via pyproject.toml force-include.
  • Update the /speckit.specify command template to consult extension enablement/config and prefer extension scripts with fallback behavior.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
templates/commands/specify.md Updates specify command flow to check git extension enablement/config and prefer extension scripts.
src/specify_cli/init.py Adds bundled-extension discovery + auto-install during specify init.
pyproject.toml Bundles extensions/git into the wheel’s core_pack.
extensions/git/extension.yml New extension manifest defining commands, hooks, and defaults.
extensions/git/config-template.yml New user-facing config template for git extension settings.
extensions/git/README.md Documentation for git extension usage, config, and behavior.
extensions/git/commands/speckit.git.feature.md Command template for creating a feature branch via extension scripts.
extensions/git/commands/speckit.git.validate.md Command template for validating branch naming conventions.
extensions/git/commands/speckit.git.remote.md Command template for detecting git remote URL safely.
extensions/git/scripts/bash/create-new-feature.sh Bash feature-creation script adapted for extension install locations.
extensions/git/scripts/bash/git-common.sh Bash git-only helper functions extracted for reuse.
extensions/git/scripts/powershell/create-new-feature.ps1 PowerShell feature-creation script adapted for extension install locations.
extensions/git/scripts/powershell/git-common.ps1 PowerShell git-only helper functions extracted for reuse.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Mar 23, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 23, 2026

@copilot apply changes based on the comments in this thread

All 9 review comments addressed in 5e49ec6 and 17810c8:

  1. Bash common.sh sourcing — checks .specify/scripts/bash/scripts/bash/git-common.sh with hard error if none found
  2. PowerShell common.ps1 sourcing — uses $fallbackRoot for reliable resolution with same priority order and error
  3. Removed branch_template/auto_fetch from extension.yml defaults and config-template.yml (not implemented in scripts)
  4. Removed unused ExtensionError import
  5. Added 2 tests for auto-install path (init flow + already-installed no-op)
  6. Fixed double branch creation — step 2 now skips when before_specify hook already executed
  7. Added explicit FEATURE_DIR/SPEC_FILE creation in disabled-git path
  8. Added PowerShell path to script resolution in specify.md
  9. Removed undocumented SPECKIT_GIT_BRANCH_NUMBERING env var from README

All 818 tests pass, CodeQL clean.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/github/spec-kit/releases/latest
    • Triggering command: `/usr/bin/python3 python3 -c
      import tempfile, shutil
      from pathlib import Path
      from typer.testing import CliRunner
      from specify_cli import app

with tempfile.TemporaryDirectory() as tmpdir:
project = Path(tmpdir) / 'test-project'
REDACTED = CliRunner()
result = REDACTED.invok` (http block)

  • Triggering command: `/usr/bin/python3 python3 -c
    import tempfile
    from pathlib import Path
    from typer.testing import CliRunner
    from specify_cli import app

with tempfile.TemporaryDirectory() as tmpdir:
project = Path(tmpdir) / 'test-project'
REDACTED = CliRunner()
result = REDACTED.invoke(app, [` (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Mar 23, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 23, 2026

@copilot apply changes based on the comments in this thread

All 7 review comments addressed in 4f1b63a and 363b7dc:

  1. Auto-install failure loggingexcept Exception now logs a [dim yellow]Warning: with details via console.print instead of silently returning False
  2. README install command — fixed --from extensions/git/extensions/git --dev
  3. README table syntax — already correct (single pipes), no change needed
  4. Bash fail-fast — added post-source check for resolve_template/json_escape; hard-fails with error listing actual tried paths
  5. PowerShell fail-fast — added post-source check for Resolve-Template; throws with paths tried
  6. PowerShell $env: prefix — fixed $env:FEATURE_DIR/$env:SPEC_FILE$FEATURE_DIR/$SPEC_FILE
  7. Docstring — updated to "Returns True if the extension was installed or already present"

All 818 tests pass, CodeQL clean.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Mar 23, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 23, 2026

@copilot apply changes based on the comments in this thread

Both comments addressed in a5466f0:

  1. Quiet git checkoutgit checkout -q -b "$BRANCH_NAME" >/dev/null 2>&1 suppresses the "Switched to a new branch…" status line that was contaminating JSON output
  2. Registry check clarification — specify.md now explicitly states: only skip branching when extensions.git.enabled is present and explicitly false; proceed normally in all other cases (missing registry, missing entry, absent enabled field)

All 818 tests pass.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mnriem
Copy link
Copy Markdown
Collaborator

mnriem commented Mar 23, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 23, 2026

@copilot apply changes based on the comments in this thread

Both comments addressed in 7396683:

  1. Stale registry detection_install_bundled_git_extension() now verifies .specify/extensions/git/extension.yml exists on disk when the registry says "installed"; if the manifest is missing, removes the stale registry entry and proceeds with reinstall
  2. Regression test — added test_git_extension_reinstalls_when_directory_missing that creates an install, deletes the extension directory (keeping the registry), and asserts reinstall succeeds

All 819 tests pass.

- Create extensions/git/ with 5 commands: initialize, feature,
  validate, remote, commit
- 18 hooks covering before/after for all 9 core commands
- Scripts: create-new-feature, initialize-repo, auto-commit,
  git-common (bash + powershell)
- Configurable: branch_numbering, init_commit_message,
  per-command auto-commit with custom messages
- Add hooks to analyze, checklist, clarify, constitution,
  taskstoissues command templates
- Allow hooks-only extensions (no commands required)
- Bundle extension in wheel via pyproject.toml force-include
- Resolve bundled extensions locally before catalog lookup
- Remove planned-but-unimplemented before/after_commit hook refs
- Update extension docs (API ref, dev guide, user guide)
- 37 new tests covering manifest, install, all scripts (bash+pwsh),
  config reading, graceful degradation

Stage 1: opt-in via 'specify extension add git'. No auto-install,
no changes to specify.md or core git init code.

Refs: #841, #1382, #1066, #1791, #1191
@mnriem mnriem force-pushed the copilot/extract-git-branching-operations branch from 7396683 to a084d09 Compare April 6, 2026 19:14
@mnriem mnriem requested a review from Copilot April 6, 2026 19:14
@mnriem mnriem changed the title Extract Git/Branching operations into extensions/git extension (opt-out, auto-enabled) feat: Git extension stage 1 — bundled extensions/git with hooks on all core commands Apr 6, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a bundled extensions/git extension to decouple Git/branching workflow behaviors from core logic, and wires extension hooks into the core command templates and CLI extension install flow to support opt-out/override workflows.

Changes:

  • Allow extension manifests with hooks-only (no commands) and add coverage for that validation.
  • Add a bundled extensions/git/ extension (manifest, commands, scripts, config template) plus tests validating install + cross-platform scripts.
  • Update core command templates and extension docs to recognize additional hook events and surface hooks in agent workflows; bundle the extension into the wheel and prefer bundled extensions during specify extension add.
Show a summary per file
File Description
tests/test_extensions.py Updates manifest validation tests for hooks-only behavior and revised error messaging.
tests/extensions/init.py Declares extensions tests package.
tests/extensions/git/init.py Declares git extension tests package.
tests/extensions/git/test_git_extension.py Adds end-to-end tests for git extension manifest, install, and scripts (bash/pwsh).
src/specify_cli/extensions.py Relaxes manifest validation to allow hooks-only extensions.
src/specify_cli/init.py Adds bundled-extension locator and prefers bundled installs in extension add.
pyproject.toml Bundles extensions/git into the wheel under core_pack/extensions/git.
templates/commands/analyze.md Adds pre/post hook discovery/output instructions for analyze workflow.
templates/commands/checklist.md Adds pre/post hook discovery/output instructions for checklist workflow.
templates/commands/clarify.md Adds pre/post hook discovery/output instructions for clarify workflow.
templates/commands/constitution.md Adds pre/post hook discovery/output instructions for constitution workflow.
templates/commands/taskstoissues.md Adds pre/post hook discovery/output instructions for tasks-to-issues workflow.
extensions/git/extension.yml Defines the bundled git extension: commands, hooks, defaults, metadata.
extensions/git/README.md Documents the git extension’s purpose/config/usage.
extensions/git/config-template.yml Provides default config for branch numbering + auto-commit behavior.
extensions/git/commands/speckit.git.feature.md Adds command template for feature branch creation via extension scripts.
extensions/git/commands/speckit.git.validate.md Adds command template for validating feature branch naming.
extensions/git/commands/speckit.git.remote.md Adds command template for remote URL detection.
extensions/git/commands/speckit.git.initialize.md Adds command template for initializing a repo via extension scripts.
extensions/git/commands/speckit.git.commit.md Adds command template for auto-commit hook behavior.
extensions/git/scripts/bash/create-new-feature.sh Extension-scoped bash implementation of feature creation.
extensions/git/scripts/bash/git-common.sh Extension-scoped bash git helpers (has_git + branch validation).
extensions/git/scripts/bash/initialize-repo.sh Extension-scoped bash repo initialization.
extensions/git/scripts/bash/auto-commit.sh Extension-scoped bash auto-commit.
extensions/git/scripts/powershell/create-new-feature.ps1 Extension-scoped PowerShell implementation of feature creation.
extensions/git/scripts/powershell/git-common.ps1 Extension-scoped PowerShell git helpers (Test-HasGit/Test-FeatureBranch).
extensions/git/scripts/powershell/initialize-repo.ps1 Extension-scoped PowerShell repo initialization.
extensions/git/scripts/powershell/auto-commit.ps1 Extension-scoped PowerShell auto-commit.
extensions/EXTENSION-USER-GUIDE.md Expands documented hook event list.
extensions/EXTENSION-DEVELOPMENT-GUIDE.md Updates extension authoring guidance for commands vs hooks and hook events.
extensions/EXTENSION-API-REFERENCE.md Updates API reference for expanded hook event taxonomy.
extensions/catalog.json Adds git extension to catalog and bumps updated_at.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (5)

templates/commands/analyze.md:45

  • Hook output hardcodes /{command} as the invocation, but the CLI supports agent-specific skill invocation modes (e.g., Codex $speckit-..., Claude /{speckit-...}, Kimi /skill:speckit-...) as implemented in HookExecutor._render_hook_invocation. To avoid telling users to run the wrong thing, emit the correct invocation form (and/or include both raw command id and rendered invocation, like EXECUTE_COMMAND_INVOCATION).
    **Optional Pre-Hook**: {extension}
    Command: `/{command}`
    Description: {description}

    Prompt: {prompt}
    To execute: `/{command}`
    ```
  - **Mandatory hook** (`optional: false`):
    ```
    ## Extension Hooks

    **Automatic Pre-Hook**: {extension}
    Executing: `/{command}`
    EXECUTE_COMMAND: {command}

templates/commands/checklist.md:66

  • Hook output hardcodes /{command} as the invocation, but the CLI supports agent-specific skill invocation modes (e.g., Codex $speckit-..., Claude /{speckit-...}, Kimi /skill:speckit-...) as implemented in HookExecutor._render_hook_invocation. To avoid telling users to run the wrong thing, emit the correct invocation form (and/or include both raw command id and rendered invocation, like EXECUTE_COMMAND_INVOCATION).
    **Optional Pre-Hook**: {extension}
    Command: `/{command}`
    Description: {description}

    Prompt: {prompt}
    To execute: `/{command}`
    ```
  - **Mandatory hook** (`optional: false`):
    ```
    ## Extension Hooks

    **Automatic Pre-Hook**: {extension}
    Executing: `/{command}`
    EXECUTE_COMMAND: {command}

templates/commands/clarify.md:48

  • Hook output hardcodes /{command} as the invocation, but the CLI supports agent-specific skill invocation modes (e.g., Codex $speckit-..., Claude /{speckit-...}, Kimi /skill:speckit-...) as implemented in HookExecutor._render_hook_invocation. To avoid telling users to run the wrong thing, emit the correct invocation form (and/or include both raw command id and rendered invocation, like EXECUTE_COMMAND_INVOCATION).
    **Optional Pre-Hook**: {extension}
    Command: `/{command}`
    Description: {description}

    Prompt: {prompt}
    To execute: `/{command}`
    ```
  - **Mandatory hook** (`optional: false`):
    ```
    ## Extension Hooks

    **Automatic Pre-Hook**: {extension}
    Executing: `/{command}`
    EXECUTE_COMMAND: {command}

templates/commands/constitution.md:45

  • Hook output hardcodes /{command} as the invocation, but the CLI supports agent-specific skill invocation modes (e.g., Codex $speckit-..., Claude /{speckit-...}, Kimi /skill:speckit-...) as implemented in HookExecutor._render_hook_invocation. To avoid telling users to run the wrong thing, emit the correct invocation form (and/or include both raw command id and rendered invocation, like EXECUTE_COMMAND_INVOCATION).
    **Optional Pre-Hook**: {extension}
    Command: `/{command}`
    Description: {description}

    Prompt: {prompt}
    To execute: `/{command}`
    ```
  - **Mandatory hook** (`optional: false`):
    ```
    ## Extension Hooks

    **Automatic Pre-Hook**: {extension}
    Executing: `/{command}`
    EXECUTE_COMMAND: {command}

templates/commands/taskstoissues.md:45

  • Hook output hardcodes /{command} as the invocation, but the CLI supports agent-specific skill invocation modes (e.g., Codex $speckit-..., Claude /{speckit-...}, Kimi /skill:speckit-...) as implemented in HookExecutor._render_hook_invocation. To avoid telling users to run the wrong thing, emit the correct invocation form (and/or include both raw command id and rendered invocation, like EXECUTE_COMMAND_INVOCATION).
    **Optional Pre-Hook**: {extension}
    Command: `/{command}`
    Description: {description}

    Prompt: {prompt}
    To execute: `/{command}`
    ```
  - **Mandatory hook** (`optional: false`):
    ```
    ## Extension Hooks

    **Automatic Pre-Hook**: {extension}
    Executing: `/{command}`
    EXECUTE_COMMAND: {command}
  • Files reviewed: 32/32 changed files
  • Comments generated: 11

mnriem added 2 commits April 6, 2026 14:23
- Fix commands property KeyError for hooks-only extensions
- Fix has_git() operator precedence in git-common.sh
- Align default commit message to '[Spec Kit] Initial commit' across
  config-template, extension.yml defaults, and both init scripts
- Update README to reflect all 5 commands and 18 hooks
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a bundled, opt-in Git extension (extensions/git/) and expands hook support so all core commands can participate in the extension hook lifecycle (before/after). It also updates extension-manifest validation to allow hooks-only extensions and adds tests covering the new bundled extension and hook behavior.

Changes:

  • Bundle a new git extension (commands + hooks + bash/PowerShell scripts + config template) and make specify extension add git resolve locally before using the catalog.
  • Expand hook support documentation/templates to include hooks for analyze, checklist, clarify, constitution, and taskstoissues.
  • Add/adjust tests for hooks-only extensions and for the bundled git extension behaviors.
Show a summary per file
File Description
tests/test_extensions.py Updates manifest validation tests to allow hooks-only extensions and adjust error message.
tests/extensions/git/test_git_extension.py Adds comprehensive tests for bundled git extension manifest, install, and scripts.
tests/extensions/git/__init__.py Marks git extension tests as a package.
tests/extensions/__init__.py Marks extensions tests as a package.
templates/commands/taskstoissues.md Adds before/after hook-check sections for task-to-issues flow.
templates/commands/constitution.md Adds before/after hook-check sections for constitution flow.
templates/commands/clarify.md Adds before/after hook-check sections for clarify flow.
templates/commands/checklist.md Adds before/after hook-check sections for checklist flow.
templates/commands/analyze.md Adds before/after hook-check sections for analyze flow.
src/specify_cli/extensions.py Allows manifests with hooks-only; adjusts commands accessor defaulting.
src/specify_cli/__init__.py Adds _locate_bundled_extension() and installs bundled extensions before catalog download.
pyproject.toml Forces extensions/git into the wheel as core_pack/extensions/git.
extensions/git/scripts/powershell/initialize-repo.ps1 Implements repo initialization (PowerShell) with config-driven commit message.
extensions/git/scripts/powershell/git-common.ps1 Adds git detection + feature-branch validation helpers (PowerShell).
extensions/git/scripts/powershell/create-new-feature.ps1 Implements feature branch creation (PowerShell) with sequential/timestamp numbering.
extensions/git/scripts/powershell/auto-commit.ps1 Implements config-driven auto-commit hook (PowerShell).
extensions/git/scripts/bash/initialize-repo.sh Implements repo initialization (bash) with config-driven commit message.
extensions/git/scripts/bash/git-common.sh Adds git detection + feature-branch validation helpers (bash).
extensions/git/scripts/bash/create-new-feature.sh Implements feature branch creation (bash) with sequential/timestamp numbering.
extensions/git/scripts/bash/auto-commit.sh Implements config-driven auto-commit hook (bash).
extensions/git/README.md Documents git extension commands, hooks, config, and install/disable usage.
extensions/git/extension.yml Declares git extension metadata, commands, hooks, and defaults.
extensions/git/config-template.yml Provides default git-config.yml template including per-event auto-commit config.
extensions/git/commands/speckit.git.validate.md Adds validation command documentation for feature-branch naming.
extensions/git/commands/speckit.git.remote.md Adds remote detection command documentation for GitHub integration.
extensions/git/commands/speckit.git.initialize.md Adds initialize command documentation and script wiring.
extensions/git/commands/speckit.git.feature.md Adds feature-branch command documentation and script wiring.
extensions/git/commands/speckit.git.commit.md Adds auto-commit command documentation and script wiring.
extensions/EXTENSION-USER-GUIDE.md Updates list of supported hook events (removes planned commit hooks).
extensions/EXTENSION-DEVELOPMENT-GUIDE.md Updates guidance: commands optional if hooks exist; expands hook event list.
extensions/EXTENSION-API-REFERENCE.md Updates hook event reference to include newly supported events.
extensions/catalog.json Adds git extension entry for discoverability and updates timestamp.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 32/32 changed files
  • Comments generated: 6

- Add type validation for provides.commands (must be list) and hooks
  (must be dict) in manifest _validate()
- Tighten malformed timestamp detection in git-common.sh to catch
  7-digit dates without trailing slug (e.g. 2026031-143022)
- Pass REPO_ROOT to has_git/Test-HasGit in create-new-feature scripts
- Fix initialize command docs: surface errors on git failures, only
  skip when git is not installed
- Fix commit command docs: 'skips with a warning' not 'silently'
- Add tests for commands:null and hooks:list rejection
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in, bundled Git extension (extensions/git) and expands the core hook surface so extensions can hook into all core commands (including analyze/checklist/clarify/constitution/taskstoissues). It also updates extension manifest validation to allow hooks-only extensions and adds tests around bundled extension installation and git scripts.

Changes:

  • Bundle and catalog a new git extension (commands, hooks, bash/PowerShell scripts, config template, docs).
  • Expand hook support in core command templates by adding pre/post hook checks to additional commands.
  • Allow extensions with no commands as long as they provide hooks, and add tests for these manifest rules plus bundled-extension installation.
Show a summary per file
File Description
src/specify_cli/extensions.py Manifest validation now allows hooks-only extensions and adds type checks for provides.commands / hooks.
src/specify_cli/__init__.py Adds bundled extension locator and installs bundled extensions before catalog downloads.
pyproject.toml Forces extensions/git into the wheel under core_pack/extensions/git.
extensions/git/** New bundled git extension: manifest, docs, config template, commands, and bash/PowerShell scripts.
templates/commands/{analyze,checklist,clarify,constitution,taskstoissues}.md Adds hook pre/post checks so hooks can run on these commands too.
extensions/EXTENSION-*.md Updates docs to reflect new hook events and hooks-only extensions.
extensions/catalog.json Adds git to catalog metadata.
tests/test_extensions.py Updates manifest validation tests for hooks-only rule and invalid hooks/commands shapes.
tests/extensions/git/test_git_extension.py New test suite validating git extension manifest, install path, and scripts behavior.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 32/32 changed files
  • Comments generated: 5

- Remove scripts frontmatter from command files (CommandRegistrar
  rewrites ../../scripts/ to .specify/scripts/ which points at core
  scripts, not extension scripts)
- Update speckit.git.commit command to derive event name from hook
  context rather than using a static example
- Clarify that hook argument passthrough works via AI agent context
  (the agent carries conversation state including user's original
  feature description)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a bundled, opt-in extensions/git extension that encapsulates Git branching/initialization/auto-commit behavior and wires extension hooks into additional core command templates, while updating manifest validation to allow hooks-only extensions and enabling local installation of bundled extensions.

Changes:

  • Add bundled extensions/git/ (commands, scripts, config template, docs) plus comprehensive tests for install + script behavior.
  • Expand hook support across additional core command templates and update extension docs to reflect the new hook events.
  • Update extension manifest validation to allow hooks-only extensions; add bundled-extension resolution for specify extension add.
Show a summary per file
File Description
src/specify_cli/extensions.py Allow hooks-only manifests; tighten provides.commands/hooks type validation.
src/specify_cli/__init__.py Add bundled-extension locator and prefer bundled install in extension add.
pyproject.toml Force-include bundled git extension into wheel core_pack/.
extensions/catalog.json Add git extension entry and refresh catalog timestamp.
extensions/EXTENSION-API-REFERENCE.md Document additional hook events; remove planned before_commit/after_commit.
extensions/EXTENSION-DEVELOPMENT-GUIDE.md Update guidance: commands optional; hooks/commands requirement clarified; expand hook list.
extensions/EXTENSION-USER-GUIDE.md Update available hook event list.
templates/commands/analyze.md Add pre/post hook-check instructions for before_analyze/after_analyze.
templates/commands/checklist.md Add pre/post hook-check instructions for before_checklist/after_checklist.
templates/commands/clarify.md Add pre/post hook-check instructions for before_clarify/after_clarify.
templates/commands/constitution.md Add pre/post hook-check instructions for before_constitution/after_constitution.
templates/commands/taskstoissues.md Add pre/post hook-check instructions for before_taskstoissues/after_taskstoissues.
tests/test_extensions.py Add manifest-validation tests for hooks-only + invalid shapes.
tests/extensions/__init__.py Define test package.
tests/extensions/git/__init__.py Define git extension test package.
tests/extensions/git/test_git_extension.py New test suite for bundled git extension install + bash/pwsh scripts.
extensions/git/extension.yml New git extension manifest (commands, hooks, config metadata, defaults).
extensions/git/README.md User-facing documentation for the git extension.
extensions/git/config-template.yml Sample configuration template for git behavior (branch numbering, auto-commit).
extensions/git/commands/speckit.git.feature.md Command template for feature-branch creation (config-aware invocation).
extensions/git/commands/speckit.git.initialize.md Command template for repository initialization.
extensions/git/commands/speckit.git.validate.md Command template for branch validation.
extensions/git/commands/speckit.git.remote.md Command template for remote URL detection.
extensions/git/commands/speckit.git.commit.md Command template for per-event auto-commit.
extensions/git/scripts/bash/create-new-feature.sh Extension-scoped bash feature-branch creation script.
extensions/git/scripts/bash/git-common.sh Extension-scoped bash git helpers (has_git, branch validation).
extensions/git/scripts/bash/initialize-repo.sh Extension-scoped bash repo init script.
extensions/git/scripts/bash/auto-commit.sh Extension-scoped bash auto-commit script (config-driven).
extensions/git/scripts/powershell/create-new-feature.ps1 Extension-scoped PowerShell feature-branch creation script.
extensions/git/scripts/powershell/git-common.ps1 Extension-scoped PowerShell git helpers.
extensions/git/scripts/powershell/initialize-repo.ps1 Extension-scoped PowerShell repo init script.
extensions/git/scripts/powershell/auto-commit.ps1 Extension-scoped PowerShell auto-commit script (config-driven).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 32/32 changed files
  • Comments generated: 5

- Validate extension_id against ^[a-z0-9-]+$ in _locate_bundled_extension
  to prevent path traversal (security fix)
- Move defaults under config.defaults in extension.yml to match
  ConfigManager._get_extension_defaults() schema
- Ship git-config.yml in extension directory so it's copied during
  install (provides.config template isn't materialized by ExtensionManager)
- Condition handling in hook templates: intentionally matches existing
  pattern from specify/plan/tasks/implement templates (not a new issue)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a bundled, opt-in extensions/git extension that encapsulates Spec Kit’s Git workflow (init/branch/validate/remote/auto-commit) and expands hook support so all core commands can participate in before/after extension hooks.

Changes:

  • Add bundled extensions/git/ (manifest, commands, config templates, bash + PowerShell scripts) plus comprehensive extension-level tests.
  • Update extension manifest validation to allow hooks-only extensions (must provide at least one command or hook).
  • Add hook-checking guidance to additional core command templates and enable local install of bundled extensions via specify extension add <id>.
Show a summary per file
File Description
tests/test_extensions.py Adds manifest validation tests for hooks-only and invalid hooks/commands types.
tests/extensions/git/test_git_extension.py New test suite covering git extension manifest + scripts + bundled locator.
tests/extensions/git/init.py Initializes git extension test package.
tests/extensions/init.py Initializes extensions test package.
templates/commands/taskstoissues.md Adds pre/post hook-check sections for tasks-to-issues command template.
templates/commands/constitution.md Adds pre/post hook-check sections for constitution command template.
templates/commands/clarify.md Adds pre/post hook-check sections for clarify command template.
templates/commands/checklist.md Adds pre/post hook-check sections for checklist command template.
templates/commands/analyze.md Adds hook-check guidance for analyze command template.
src/specify_cli/extensions.py Allows manifests with hooks-only; adds stricter type checks for commands/hooks.
src/specify_cli/init.py Adds _locate_bundled_extension() + installs bundled extensions before catalog fallback.
pyproject.toml Force-includes extensions/git into wheel core_pack.
extensions/git/scripts/powershell/initialize-repo.ps1 New PS repo init script for git extension.
extensions/git/scripts/powershell/git-common.ps1 New PS git helper functions (has git, feature-branch validation).
extensions/git/scripts/powershell/create-new-feature.ps1 New PS feature-branch creation script for git extension.
extensions/git/scripts/powershell/auto-commit.ps1 New PS auto-commit script for git extension.
extensions/git/scripts/bash/initialize-repo.sh New bash repo init script for git extension.
extensions/git/scripts/bash/git-common.sh New bash git helper functions (has git, feature-branch validation).
extensions/git/scripts/bash/create-new-feature.sh New bash feature-branch creation script for git extension.
extensions/git/scripts/bash/auto-commit.sh New bash auto-commit script for git extension.
extensions/git/README.md Documents git extension commands, hooks, config, and install/disable workflow.
extensions/git/git-config.yml Default git extension configuration (auto-commit disabled by default).
extensions/git/extension.yml Git extension manifest (commands + hooks + config template).
extensions/git/config-template.yml Config template copied into project on install.
extensions/git/commands/speckit.git.validate.md Command doc for branch validation behavior.
extensions/git/commands/speckit.git.remote.md Command doc for remote URL detection behavior.
extensions/git/commands/speckit.git.initialize.md Command doc for repo initialization behavior.
extensions/git/commands/speckit.git.feature.md Command doc for feature-branch creation behavior.
extensions/git/commands/speckit.git.commit.md Command doc for hook-driven auto-commit behavior.
extensions/EXTENSION-USER-GUIDE.md Updates documented list of hook events (removes before/after_commit).
extensions/EXTENSION-DEVELOPMENT-GUIDE.md Updates extension authoring guidance for hooks-only + expanded hook events.
extensions/EXTENSION-API-REFERENCE.md Updates hook event reference list to include newly supported events.
extensions/catalog.json Adds git extension to catalog for discoverability and updates updated_at.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 33/33 changed files
  • Comments generated: 3

Comment on lines +17 to +46
| Command | Description |
|---------|-------------|
| `speckit.git.initialize` | Initialize a Git repository with a configurable commit message |
| `speckit.git.feature` | Create a feature branch with sequential or timestamp numbering |
| `speckit.git.validate` | Validate current branch follows feature branch naming conventions |
| `speckit.git.remote` | Detect Git remote URL for GitHub integration |
| `speckit.git.commit` | Auto-commit changes (configurable per-command enable/disable and messages) |

## Hooks

| Event | Command | Optional | Description |
|-------|---------|----------|-------------|
| `before_constitution` | `speckit.git.initialize` | No | Init git repo before constitution |
| `before_specify` | `speckit.git.feature` | No | Create feature branch before specification |
| `before_clarify` | `speckit.git.commit` | Yes | Commit outstanding changes before clarification |
| `before_plan` | `speckit.git.commit` | Yes | Commit outstanding changes before planning |
| `before_tasks` | `speckit.git.commit` | Yes | Commit outstanding changes before task generation |
| `before_implement` | `speckit.git.commit` | Yes | Commit outstanding changes before implementation |
| `before_checklist` | `speckit.git.commit` | Yes | Commit outstanding changes before checklist |
| `before_analyze` | `speckit.git.commit` | Yes | Commit outstanding changes before analysis |
| `before_taskstoissues` | `speckit.git.commit` | Yes | Commit outstanding changes before issue sync |
| `after_constitution` | `speckit.git.commit` | Yes | Auto-commit after constitution update |
| `after_specify` | `speckit.git.commit` | Yes | Auto-commit after specification |
| `after_clarify` | `speckit.git.commit` | Yes | Auto-commit after clarification |
| `after_plan` | `speckit.git.commit` | Yes | Auto-commit after planning |
| `after_tasks` | `speckit.git.commit` | Yes | Auto-commit after task generation |
| `after_implement` | `speckit.git.commit` | Yes | Auto-commit after implementation |
| `after_checklist` | `speckit.git.commit` | Yes | Auto-commit after checklist |
| `after_analyze` | `speckit.git.commit` | Yes | Auto-commit after analysis |
| `after_taskstoissues` | `speckit.git.commit` | Yes | Auto-commit after issue sync |
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Markdown tables are written with a double leading pipe (|| ...), which renders as an extra empty column in most Markdown parsers. Use the standard | col | col | syntax for both the header and rows so the tables render correctly on GitHub.

Copilot uses AI. Check for mistakes.
# Initialize
_git_out=$(git init -q 2>&1) || { echo "[specify] Error: git init failed: $_git_out" >&2; exit 1; }
_git_out=$(git add . 2>&1) || { echo "[specify] Error: git add failed: $_git_out" >&2; exit 1; }
_git_out=$(git commit -q -m "$COMMIT_MSG" 2>&1) || { echo "[specify] Error: git commit failed: $_git_out" >&2; exit 1; }
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git commit will fail in an otherwise-empty repo ("nothing to commit") because the script doesn't use --allow-empty. Since this script is meant to initialize a repo reliably, consider adding --allow-empty (or ensuring at least one file exists) so initialization succeeds even when there are no tracked files yet.

Suggested change
_git_out=$(git commit -q -m "$COMMIT_MSG" 2>&1) || { echo "[specify] Error: git commit failed: $_git_out" >&2; exit 1; }
_git_out=$(git commit --allow-empty -q -m "$COMMIT_MSG" 2>&1) || { echo "[specify] Error: git commit failed: $_git_out" >&2; exit 1; }

Copilot uses AI. Check for mistakes.
if ($LASTEXITCODE -ne 0) { throw "git init failed: $out" }
$out = git add . 2>&1 | Out-String
if ($LASTEXITCODE -ne 0) { throw "git add failed: $out" }
$out = git commit -q -m $commitMsg 2>&1 | Out-String
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git commit can fail in an otherwise-empty repo ("nothing to commit") because it isn't run with --allow-empty. Since this script is intended to initialize a repo robustly, consider using --allow-empty (or ensuring at least one file exists) so initialization succeeds even when there are no files to commit yet.

Suggested change
$out = git commit -q -m $commitMsg 2>&1 | Out-String
$out = git commit --allow-empty -q -m $commitMsg 2>&1 | Out-String

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extract Git/Branching Operations into extensions/git Extension (Opt-Out, Auto-Enabled)

3 participants